/*!
 * @file        usb_user.c
 *
 * @brief       usb user configuration
 *
 * @version     V1.0.0
 *
 * @date        2022-05-25
 *
 */
#include "usb_user.h"
#include "usbh_core.h"
#include "usb_board.h"
#include "usbh_class_cdc.h"

static void USER_InitHandler(void);
static void USER_DeInitHandler(void);
static void USER_ResetDevHandler(void);
static void USER_DevAttachedHandler(void);
static void USER_DevDetachedHandler(void);
static void USER_DevSpeedDetectedHandler(uint8_t speed);
static void USER_DevDescHandler(void *devDesc);
static void USER_CfgDescHandler(void *cfgDesc, void *interface);
static void USER_ManufacturerStringHandler(void *mfcDesc);
static void USER_ProductStringHandler(void *productDesc);
static void USER_SerialNumStringHandler(void *serialDesc);
static void USER_EnumDoneHandler(void);
static USER_STATE_T USER_UserInputHandler(void);
static USER_STATE_T USER_ApplicationHandler(void);
static void USER_DeviceNotSupportedHandler(void);
static void USER_UnrecoveredErrHandler(void);

#if (DELAY_SOURCE != USE_DEFAULT)
static void USB_USER_Delay(uint32_t cnt);
#endif

USB_UserCallBack_T g_userCallback =
{
    USER_InitHandler,
    USER_DeInitHandler,
    USER_ResetDevHandler,
    USER_DevAttachedHandler,
    USER_DevDetachedHandler,
    USER_DevSpeedDetectedHandler,
    USER_DevDescHandler,
    USER_CfgDescHandler,
    USER_ManufacturerStringHandler,
    USER_ProductStringHandler,
    USER_SerialNumStringHandler,
    USER_EnumDoneHandler,
    USER_UserInputHandler,
    USER_ApplicationHandler,
    USER_DeviceNotSupportedHandler,
    USER_UnrecoveredErrHandler,

#if (DELAY_SOURCE == USE_DEFAULT)
    NULL
#else
    USB_USER_Delay
#endif
};

/*!
 * @brief       User Initialization Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_InitHandler(void)
{
    USART_Config_T usartConfig;

    /** Configure USART */
    usartConfig.baudRate = 115200;
    usartConfig.wordLength = USART_WORD_LEN_8B;
    usartConfig.stopBits = USART_STOP_BIT_1;
    usartConfig.parity = USART_PARITY_NONE ;
    usartConfig.mode = USART_MODE_TX_RX;
    usartConfig.hardwareFlow = USART_HARDWARE_FLOW_NONE;

    APM_BOARD_COMInit(COM1,&usartConfig);

    APM_EVAL_LEDInit(LED2);
    APM_EVAL_LEDInit(LED3);

    APM_EVAL_PBInit(BUTTON_KEY2, BUTTON_MODE_EINT);
    APM_EVAL_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);
}

/*!
 * @brief       User Re-Initialization Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_DeInitHandler(void)
{
    printf(">> Host Re-Initialize.\r\n");
}

/*!
 * @brief       User Reset Device Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_ResetDevHandler(void)
{
    printf(">> Reset USB Device.\r\n");
}

/*!
 * @brief       User Device Attached Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_DevAttachedHandler(void)
{
    printf(">> Device Attached.\r\n");
}

/*!
 * @brief       User Device Detached Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_DevDetachedHandler(void)
{
    printf(">> Device Disconnected.\r\n");
}

/*!
 * @brief       User Device Speed Detected Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_DevSpeedDetectedHandler(uint8_t speed)
{
    switch (speed)
    {
        case USBH_DEVICE_SPEED_HS:
            printf(">> Device Speed : High Speed.\r\n");
            break;
        case USBH_DEVICE_SPEED_FS:
            printf(">> Device Speed : Full Speed.\r\n");
            break;
        case USBH_DEVICE_SPEED_LS:
            printf(">> Device Speed : Low Speed.\r\n");
            break;
        default :
            printf(">> Unknown Speed.\r\n");
            break;
    }
}

/*!
 * @brief       User got Device Descriptor Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_DevDescHandler(void *devDesc)
{
    USBH_DeviceDesc_T *desc = devDesc;

    printf(">> VID : 0x%04X\r\n", desc->idVendor[0] | desc->idVendor[1] << 8);
    printf(">> PID : 0x%04X\r\n", desc->idProduct[0] | desc->idProduct[1] << 8);
    printf(">> Endpoint 0 max pack size is %d\r\n", desc->bMaxPacketSize);
}

/*!
 * @brief       User got Configuration Descriptor Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_CfgDescHandler(void *cfgDesc, void *interface)
{
    USBH_Interface_T *itf = interface;
    uint8_t i;

    switch (itf->itfDesc.bInterfaceClass)
    {
        case 0x08:
            printf(">> This is a Mass Storage Class Device.\r\n");
            break;
        case 0x03:
            printf(">> This is a HID Class Device.\r\n");
            break;
        case 0x0A:
            printf(">> This is a Communications Class Device.\r\n");
            break;
        default :
            printf(">> Class Code is : 0x%02X\r\n", itf->itfDesc.bInterfaceClass);
            break;
    }
    printf(">> Use %d endpoint:\r\n", itf->itfDesc.bNumEndpoints);
    for (i = 0; i < itf->itfDesc.bNumEndpoints; i++)
    {
        printf("    Endpoint 0x%02X: max pack size is %d bytes\r\n", \
        itf->epDesc[i].bEndpointAddress,
        itf->epDesc[i].wMaxPacketSize[0] | itf->epDesc[i].wMaxPacketSize[1] << 8);
    }
}

/*!
 * @brief       User got Manufacturer String Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_ManufacturerStringHandler(void *mfcDesc)
{
    printf(">> Manufacturer : %s\r\n", (uint8_t*)mfcDesc);
}

/*!
 * @brief       User got Product String Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_ProductStringHandler(void *productDesc)
{
    printf(">> Product : %s\r\n", (uint8_t*)productDesc);
}

/*!
 * @brief       User got Serial Number String Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_SerialNumStringHandler(void *serialDesc)
{
    printf(">> SerialNumber : %s\r\n", (uint8_t*)serialDesc);
}

/*!
 * @brief       User Enum Done Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_EnumDoneHandler(void)
{
    printf(">> USB Enum Done.\r\n");
}

/*!
 * @brief       User input Handler, Host will not go to class phase if
 *              the return value is not OK.
 *
 * @param       None
 *
 * @retval      status to show OK or not.
 */
static USER_STATE_T USER_UserInputHandler(void)
{
    return USER_OK;
}

/*!
 * @brief       User Application polling Handler
 *
 * @param       None
 *
 * @retval      status to show OK or not.
 */
static USER_STATE_T USER_ApplicationHandler(void)
{
    CDC_DEMO();

    USBH_CDCProcessSend();
    USBH_CDCProcessGet();

    return USER_OK;
}

/*!
 * @brief       User Device is not supported Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_DeviceNotSupportedHandler(void)
{
    printf(">> Device is not Supported!\r\n");
}

/*!
 * @brief       User Unrecovered Error Handler
 *
 * @param       None
 *
 * @retval      None
 */
static void USER_UnrecoveredErrHandler(void)
{
    printf(">> Unrecovered Error!\r\n");
}

/*!
 * @brief       User Delay Functionn
 *
 * @param       cnt : delay counter for us
 *
 * @retval      None
 */
#if (DELAY_SOURCE != USE_DEFAULT)
static void USB_USER_Delay(uint32_t cnt)
{
    USB_usDelay(cnt);
}
#endif
